import { Vec3 } from 'cc';
import {
  MOVEMENT_HIT_PENALTY_FACTOR,
  SPREAD_FLOOR,
  NEAR_RANGE_THRESHOLD,
  LASER_HIT_BONUS,
} from '../shared';
import type { WeaponStats, HitResult } from '../shared';
import { hasLineOfSight } from '../math/LoS';
import type { Random } from '../math/Random';

interface FireParams {
  origin: Vec3;
  targetId: string;
  targetPosition: Vec3;
  weapon: WeaponStats;
  speedNorm: number;
  laserAssist: boolean;
  random: Random;
}

export class Ballistics {
  static fire(params: FireParams): HitResult[] {
    const { origin, targetPosition, weapon, speedNorm, laserAssist, random, targetId } = params;

    if (!hasLineOfSight(origin, targetPosition)) {
      return [];
    }

    const distance = Vec3.distance(origin, targetPosition);
    const hitCoefficient = Math.max(0, 1 - MOVEMENT_HIT_PENALTY_FACTOR * Math.min(Math.max(speedNorm, 0), 1));

    let spread = Math.max(weapon.spread * (1 - weapon.attachments.spreadBonus), SPREAD_FLOOR);
    if (laserAssist && distance <= NEAR_RANGE_THRESHOLD) {
      spread *= 1 - LASER_HIT_BONUS;
    }

    const results: HitResult[] = [];
    const pellets = Math.max(1, weapon.pellets);
    const baseDamage = weapon.baseDamage;
    const effectiveCritChance = Math.min(1, weapon.critChance + weapon.attachments.critBonus);
    const penetrationCapacity = weapon.pierce + weapon.attachments.penetrationBonus;

    for (let pellet = 0; pellet < pellets; pellet++) {
      const hitChance = Math.max(0, hitCoefficient - spread * random.next());
      if (random.next() > hitChance) {
        continue;
      }
      const isCrit = random.next() < effectiveCritChance;
      const damage = baseDamage * (isCrit ? weapon.critMultiplier : 1);
      const pierceLeft = Math.max(0, Math.floor(penetrationCapacity));
      results.push({
        dstId: targetId,
        dmg: damage,
        isCrit,
        pierceLeft,
      });
    }

    return results;
  }
}


